// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------
// Modification history:
// feature: authentication-free shared key and token derivation between clients
// feature: change E2E packet format
// feature: support auth token
// feature: develop dispatcher
// feature: E2E New Requirement Development
// feature: Development of new requirements for E2E functionality
// ------------------------------------------------------------------

#ifndef _EDDS_ENTITYRTPS_CDRMESSAGECREATOR_H_
#define _EDDS_ENTITYRTPS_CDRMESSAGECREATOR_H_
#ifndef DOXYGEN_SHOULD_SKIP_THIS_PUBLIC

#include <edds/rtps/common/CDRMessage_t.h>
#include <edds/rtps/common/Guid.h>
#include <edds/rtps/common/SequenceNumber.h>
#include <edds/rtps/common/FragmentNumber.h>
#include <history/CacheChange.h>
#include <edds/rtps/common/E2EProfile04_t.h>

namespace evbs {
namespace ertps {
namespace rtps {

//!An interface to add inline qos parameters to a CDRMessage
class InlineQosWriter {
 public:
    virtual ~InlineQosWriter() = default;

    /**
     * Writes inline QOS parameters to a CDRMessage.
     * @param msg Pointer to the message.
     * @return true if writing was successful, false otherwise.
     */
    virtual bool writeQosToCDRMessage(CDRMessage_t* msg) = 0;
};

/**
 * @brief Class RTPSMessageCreator, allows the generation of serialized CDR RTPS Messages.
 * @ingroup MANAGEMENT_MODULE
 */
class RTPSMessageCreator {
 public:
    RTPSMessageCreator() = delete;
    ~RTPSMessageCreator() = delete;

    /**
     * Create a Header to the serialized message.
     * @param msg Pointer to the Message.
     * @param Prefix RTPSParticipant prefix of the message.
     * @return True if correct.
     */
    static bool addHeader(CDRMessage_t* msg, const GuidPrefix_t& Prefix);

    /**
     * Add a custom content to the serialized message.
     * @param msg Pointer to the Message.
     * @param content content to create.
     * @param contentSize size of the content.
     * @return True if correct.
     */
    static bool addCustomContent(CDRMessage_t* msg, const octet* content, const size_t contentSize);
    /**
     * Create SubmessageHeader.
     * @param msg Pointer to the CDRMessage.
     * @param id SubMessage Id.
     * @param flags Submessage flags.
     * @param size Submessage size.
     * @return True if correct.
     */
    static bool addSubmessageHeader(CDRMessage_t* msg, octet id, octet flags, uint16_t size);

    /** @name CDR messages creation methods.
     * These methods create a CDR message for different types
     * Depending on the function a complete message (with RTPS Header is created) or only the
     * submessage.
     * @param[out] msg Pointer to where the message is going to be created and stored.
     * @param[in] guidPrefix Guid Prefix of the RTPSParticipant.
     * @param[in] param Different parameters depending on the message.
     * @return True if correct.
     */

    /// @{

    static bool addSubmessageDataSingle(CDRMessage_t* msg, const CacheChange_t* change, TopicKind_t topicKind,
                                        const EntityId_t& readerId, InlineQosWriter* inlineQos,
                                        bool* is_big_submessage);

    static bool addSubmessageDataBatch(CDRMessage_t* msg, const CacheChange_t* change, TopicKind_t topicKind,
                                       const EntityId_t& readerId, InlineQosWriter* inlineQos, bool* is_big_submessage);

    static bool addSubmessageData(CDRMessage_t* msg, const CacheChange_t* change, TopicKind_t topicKind,
                                  const EntityId_t& readerId, InlineQosWriter* inlineQos, bool* is_big_submessage);

    static bool addSubmessageDataFrag(CDRMessage_t* msg, const CacheChange_t* change, uint32_t fragment_number,
                                      const CacheChange_t& change_to_add, TopicKind_t topicKind,
                                      const EntityId_t& readerId, InlineQosWriter* inlineQos);

    static bool addMessageGap(CDRMessage_t* msg, const GuidPrefix_t& guidprefix, const GuidPrefix_t& remoteGuidPrefix,
                              const SequenceNumber_t& seqNumFirst, const SequenceNumberSet_t& seqNumList,
                              const EntityId_t& readerId, const EntityId_t& writerId);
    static bool addSubmessageGap(CDRMessage_t* msg, const SequenceNumber_t& seqNumFirst,
                                 const SequenceNumberSet_t& seqNumList, const EntityId_t& readerId,
                                 const EntityId_t& writerId);

    static bool addMessageHeartbeat(CDRMessage_t* msg, const GuidPrefix_t& guidprefix, const EntityId_t& readerId,
                                    const EntityId_t& writerId, const SequenceNumber_t& firstSN,
                                    const SequenceNumber_t& lastSN, Count_t count, bool isFinal, bool livelinessFlag);
    static bool addMessageHeartbeat(CDRMessage_t* msg, const GuidPrefix_t& guidprefix,
                                    const GuidPrefix_t& remoteGuidprefix, const EntityId_t& readerId,
                                    const EntityId_t& writerId, const SequenceNumber_t& firstSN,
                                    const SequenceNumber_t& lastSN, Count_t count, bool isFinal, bool livelinessFlag);
    static bool addSubmessageHeartbeat(CDRMessage_t* msg, const EntityId_t& readerId, const EntityId_t& writerId,
                                       const SequenceNumber_t& firstSN, const SequenceNumber_t& lastSN, Count_t count,
                                       bool isFinal, bool livelinessFlag);
    static bool addSubmessageHeartbeat(CDRMessage_t* msg, const EntityId_t& readerId, const EntityId_t& writerId,
                                       const SequenceNumber_t& firstBatchSN, const SequenceNumber_t& lastBatchSN,
                                       const SequenceNumber_t& firstSN, const SequenceNumber_t& lastSN, Count_t count,
                                       bool isFinal, bool livelinessFlag);

    static bool addMessageHeartbeatFrag(CDRMessage_t* msg, const GuidPrefix_t& guidprefix, const EntityId_t& readerId,
                                        const EntityId_t& writerId, SequenceNumber_t& firstSN, FragmentNumber_t& lastFN,
                                        Count_t count);
    static bool addSubmessageHeartbeatFrag(CDRMessage_t* msg, const EntityId_t& readerId, const EntityId_t& writerId,
                                           SequenceNumber_t& firstSN, FragmentNumber_t& lastFN, Count_t count);

    static bool addMessageAcknack(CDRMessage_t* msg, const GuidPrefix_t& guidprefix,
                                  const GuidPrefix_t& remoteGuidPrefix, const EntityId_t& readerId,
                                  const EntityId_t& writerId, const SequenceNumberSet_t& SNSet, int32_t count,
                                  bool finalFlag);
    static bool addSubmessageAcknack(CDRMessage_t* msg, const EntityId_t& readerId, const EntityId_t& writerId,
                                     const SequenceNumberSet_t& SNSet, int32_t count, bool finalFlag);

    static bool addMessageNackFrag(CDRMessage_t* msg, const GuidPrefix_t& guidprefix,
                                   const GuidPrefix_t& remoteGuidPrefix, const EntityId_t& readerId,
                                   const EntityId_t& writerId, SequenceNumber_t& writerSN, FragmentNumberSet_t fnState,
                                   int32_t count);
    static bool addSubmessageNackFrag(CDRMessage_t* msg, const EntityId_t& readerId, const EntityId_t& writerId,
                                      const SequenceNumber_t& writerSN, FragmentNumberSet_t fnState, int32_t count);

    static bool addSubmessageInfoTS(CDRMessage_t* msg, const Time_t& time, bool invalidateFlag);
    static bool addSubmessageInfoTS_Now(CDRMessage_t* msg, bool invalidateFlag);

    static bool addSubmessageInfoSRC(CDRMessage_t* msg, const ProtocolVersion_t& version, const VendorId_t& vendorId,
                                     const GuidPrefix_t& guidP);
    static bool addSubmessageInfoDST(CDRMessage_t* msg, const GuidPrefix_t& guidP);

    static bool addSubmessageInfoE2E(CDRMessage_t* msg, const EntityId_t& readerId, CacheChange_t& change);

#if HAVE_SECURITY
    static bool addSubmessageAuthToken(CDRMessage_t* msg, uint32_t token);
    static bool addSubmessageSharedKey(CDRMessage_t* msg, const std::vector<uint8_t>& shared_key);
#endif
};
}  // namespace rtps
}  // namespace ertps
} /* namespace evbs */
#endif  // ifndef DOXYGEN_SHOULD_SKIP_THIS_PUBLIC
#endif  /* _EDDS_ENTITYRTPS_CDRMESSAGECREATOR_H_ */
